// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/objects/string-comparator.h"

#include "src/objects/string-inl.h"

namespace v8 {
namespace internal {

    void StringComparator::State::Init(String string)
    {
        ConsString cons_string = String::VisitFlat(this, string);
        iter_.Reset(cons_string);
        if (!cons_string.is_null()) {
            int offset;
            string = iter_.Next(&offset);
            String::VisitFlat(this, string, offset);
        }
    }

    void StringComparator::State::Advance(int consumed)
    {
        DCHECK(consumed <= length_);
        // Still in buffer.
        if (length_ != consumed) {
            if (is_one_byte_) {
                buffer8_ += consumed;
            } else {
                buffer16_ += consumed;
            }
            length_ -= consumed;
            return;
        }
        // Advance state.
        int offset;
        String next = iter_.Next(&offset);
        DCHECK_EQ(0, offset);
        DCHECK(!next.is_null());
        String::VisitFlat(this, next);
    }

    bool StringComparator::Equals(String string_1, String string_2)
    {
        int length = string_1->length();
        state_1_.Init(string_1);
        state_2_.Init(string_2);
        while (true) {
            int to_check = Min(state_1_.length_, state_2_.length_);
            DCHECK(to_check > 0 && to_check <= length);
            bool is_equal;
            if (state_1_.is_one_byte_) {
                if (state_2_.is_one_byte_) {
                    is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
                } else {
                    is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
                }
            } else {
                if (state_2_.is_one_byte_) {
                    is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
                } else {
                    is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
                }
            }
            // Looping done.
            if (!is_equal)
                return false;
            length -= to_check;
            // Exit condition. Strings are equal.
            if (length == 0)
                return true;
            state_1_.Advance(to_check);
            state_2_.Advance(to_check);
        }
    }

} // namespace internal
} // namespace v8
